﻿using System;
using System.Collections.Generic;
using StockholmsStad.Data.Interfaces;
using StockholmsStad.Runtime.Serialization.DataContract;
using StockholmsStad.Runtime.Serialization.DataContract.Enums;
using StockholmsStad.Utilities;
using StockholmsStad.Utilities.Enums;
using StockholmsStad.Utilities.Exceptions;

namespace StockholmsStad.Business
{
    /// <summary>
    /// Hanterar affärslogik kring ceremonier
    /// </summary>
    public class CeremonyBusiness : BusinessBase
    {
        private const bool useTransaction = true;

        /// <summary>
        /// Skapar nytt affärsobjekt
        /// </summary>
        /// <param name="user"></param>
        public CeremonyBusiness(User user)
            : base(user)
        {
        }

        /// <summary>
        /// Hämta certifikatspråken
        /// </summary>
        /// <returns>En lista med språket</returns>
        public IList<ValueIdPair> GetCertificateLanguages()
        {
            var agent = AgentFactory.GetLanguageAgent();
            using (IDataContext context = GetDataContext(false))
            {   
                return agent.GetCertificateLanguages(context);
            }
        }

        /// <summary>
        /// Hämta ceremonispråken
        /// </summary>
        /// <returns>En lista med språket</returns>
        public List<ValueIdPair> GetCeremonyLanguages()
        {
            var agent = AgentFactory.GetLanguageAgent();
            using (IDataContext context = GetDataContext(false))
            {
                return agent.GetCeremonyLanguages(context);
            }
        }

        /// <summary>
        /// Hämtar standarsspråket från databasen
        /// </summary>
        /// <returns>Standardspråket</returns>
        public ValueIdPair GetDefaultLangauage()
        {
            var agent = AgentFactory.GetLanguageAgent();
            using (IDataContext context = GetDataContext(false))
            {
                return agent.GetDefaultLanguage(context);
            }
        }

        /// <summary>
        /// Hämta ceremonityperna
        /// </summary>
        /// <returns>En lista med språket</returns>
        public List<ValueIdPair> GetCeremonyTypes()
        {
            var returnValue = new List<ValueIdPair>
                                  {
                                      new ValueIdPair
                                          {
                                              Id = (int) CeremonyType.Ordinary,
                                              Name = CeremonyType.Ordinary.ToString(),
                                              Description = EnumUtility.GetEnumDescription(CeremonyType.Ordinary),
                                          },
                                      new ValueIdPair
                                          {
                                              Id = (int) CeremonyType.Individual,
                                              Name = CeremonyType.Individual.ToString(),
                                              Description = EnumUtility.GetEnumDescription(CeremonyType.Individual),
                                          },
                                  };
            return returnValue;
        }

        /// <summary>
        /// Hämta lista på hjälpmedel
        /// </summary>
        /// <returns>En lista med språket</returns>
        public List<ValueIdPair> GetCeremonySpecialNeeds()
        {
            ICeremonyAgent agent = AgentFactory.GetCeremonyAgent();
            using (IDataContext context = GetDataContext(false))
            {
                return agent.GetSpecialNeeds(context);
            }
        }

        /// <summary>
        /// Uppdaterar ceremoniinformationen
        /// </summary>
        /// <param name="ceremony"></param>
        /// <param name="ticketId"></param>
        public void UpdateCeremony(Ceremony ceremony, int ticketId)
        {
            if (CurrentUser.Role == UserRole.ReadOnly || CurrentUser.Role == UserRole.Customer)
                throw new StockholmStadSystemException(SystemErrorCode.AccessDenied);

            using (IDataContext context = GetDataContext(true))
            {
                var agent = AgentFactory.GetCeremonyAgent();
                var ticketAgent = AgentFactory.GetTicketAgent();
                var ceremonyId = agent.GetCeremonyId(context, ticketId);
                var ticket = ticketAgent.GetTicket(context, ticketId);

                agent.UpdateCeremony(context, ceremonyId, ceremony);

                var bookingAgent = AgentFactory.GetBookingAgent();

                if (bookingAgent.HasTicketBooking(context, ticketId))
                {
                    var booking = bookingAgent.GetBooking(context, ticketId);
                    agent.UpdateCeremonyBookingDetails(context, ceremonyId, ceremony, booking);

                    if (ceremony.ImpedimentDocIssuedDate.HasValue)
                    {
                        var propAgent = AgentFactory.GetPropertiesAgent();
                        var properties = propAgent.GetProperties(context);
                        //Dra bort en dag så att tiden inte spelar någon roll vid jämförelsen
                        var earliestValidDate = booking.DateTime.StartDateTime.AddMonths(-properties.ImpedimentDocValidMonths).AddDays(-1);
                        //Kontrollera om HP är inom giltighetstiden
                        if (ceremony.ImpedimentDocIssuedDate.Value > earliestValidDate)
                        {
                            ticketAgent.UpdateTicketStatus(context, ticketId, TicketStatusType.Confirmed);
                        }
                        else
                        {
                            throw new StockholmStadSystemException(SystemErrorCode.ImpedimentDocIsNotValid);
                        }
                    }
                    agent.SendConfirmedBookingMail(context, ceremonyId, ticket, booking.DateTime.StartDateTime);
                }

                context.TransactionComplete();
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="dateTime"></param>
        /// <returns></returns>
        public List<CeremonySummary> GetIndividualCeremonyBooking(DateTime dateTime)
        {
            ICeremonyAgent agent = AgentFactory.GetCeremonyAgent();
            using (IDataContext context = GetDataContext(false))
            {
                return agent.GetIndividualCeremonyBooking(context, dateTime);
            }            
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="fromDate"></param>
        /// <param name="toDate"></param>
        /// <param name="ministerId"></param>
        /// <returns></returns>
        public List<CeremonySummary> GetIndividualCeremonyBooking(DateTime fromDate, DateTime? toDate, int? ministerId)
        {
            ICeremonyAgent agent = AgentFactory.GetCeremonyAgent();
            using (IDataContext context = GetDataContext(false))
            {
                return agent.GetIndividualCeremonyBooking(context, fromDate, toDate, ministerId);
            }                        
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="dateTime"></param>
        /// <param name="ministerId"></param>
        /// <returns></returns>
        public List<CeremonySummaryDetails> GetIndividualCeremonyBookingDetails(DateTime dateTime, int? ministerId)
        {
            ICeremonyAgent agent = AgentFactory.GetCeremonyAgent();
            using (IDataContext context = GetDataContext(false))
            {
                return agent.GetIndividualCeremonyBookingDetails(context, dateTime, ministerId);
            }            
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="dateTime"></param>
        /// <returns></returns>
        public List<CeremonySummary> GetOrdinaryCeremonyBooking(DateTime dateTime)
        {
            ICeremonyAgent agent = AgentFactory.GetCeremonyAgent();
            using (IDataContext context = GetDataContext(false))
            {
                return agent.GetOrdinaryCeremonyBooking(context, dateTime);
            }            
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="fromDate"></param>
        /// <param name="toDate"></param>
        /// <param name="ministerId"></param>
        /// <returns></returns>
        public List<CeremonySummary> GetOrdinaryCeremonyBooking(DateTime fromDate, DateTime? toDate, int? ministerId)
        {
            ICeremonyAgent agent = AgentFactory.GetCeremonyAgent();
            using (IDataContext context = GetDataContext(false))
            {
                return agent.GetOrdinaryCeremonyBooking(context, fromDate, toDate, ministerId);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="dateTime"></param>
        /// <returns></returns>
        public List<CeremonySummaryDetails> GetOrdinaryCeremonyBookingDetails(DateTime dateTime)
        {
            ICeremonyAgent agent = AgentFactory.GetCeremonyAgent();
            using (IDataContext context = GetDataContext(false))
            {
                return agent.GetOrdinaryCeremonyBookingDetails(context, dateTime);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public DateTime GetNextCeremonyDateForIndividualService()
        {
            ICeremonyAgent agent = AgentFactory.GetCeremonyAgent();
            using (IDataContext context = GetDataContext(false))
            {
                return agent.GetNextCeremonyDateForIndividualService(context);
            }            
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public DateTime GetNextCeremonyDateForOrdinaryService()
        {
            ICeremonyAgent agent = AgentFactory.GetCeremonyAgent();
            using (IDataContext context = GetDataContext(false))
            {
                return agent.GetNextCeremonyDateForOrdinaryService(context);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public DateTime GetPreviousCeremonyDateForIndividualService()
        {
            ICeremonyAgent agent = AgentFactory.GetCeremonyAgent();
            using (IDataContext context = GetDataContext(false))
            {
                return agent.GetPreviousCeremonyDateForIndividualService(context);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public DateTime GetPreviousCeremonyDateForOrdinaryService()
        {
            ICeremonyAgent agent = AgentFactory.GetCeremonyAgent();
            using (IDataContext context = GetDataContext(false))
            {
                return agent.GetPreviousCeremonyDateForOrdinaryService(context);
            }
        }
    }
}